package org.jeecg.modules.ocr;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import nu.pattern.OpenCV;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.ocr.detection.verificationcode.DebugUtil;
import org.jeecg.modules.ocr.detection.verificationcode.VerficationCodeOCR;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Api(tags = "验证码处理")
@RestController
@RequestMapping("/ocr")
public class OcrCtrl {


    ;

    @Autowired
    private Environment env;

    @ApiOperation("测试1")
    @RequestMapping(value = "/test1", method = RequestMethod.GET)
    public Result<?> test1() {
        OpenCV.loadShared();
        OpenCV.loadLocally();
        for (int i = 1; i <= 20; i++) {
            DebugUtil.inputPicName = String.valueOf(i);

            String imgPath = this.getClass().getClassLoader().getResource("verificationcode/" + DebugUtil.inputPicName + DebugUtil.inputPicSuffix).getPath();
            imgPath = imgPath.substring(1, imgPath.length());

            Mat origin = Imgcodecs.imread(imgPath);

            new VerficationCodeOCR().doOCR(origin);
        }
        return Result.ok();
    }

    @ApiOperation("测试2")
    @RequestMapping(value = "/test2", method = RequestMethod.GET)
    public Result<?> test2() {
        OpenCV.loadShared();
        OpenCV.loadLocally();
//        String path = env.getProperty("jeecg.path.upload");
//        DebugUtil.testPath = path+"\\OCR\\verificationcode\\result";
        DebugUtil.inputPicName = "temp";
        String imgPath = "e:\\doc\\20191108121054.png";
        //imgPath = imgPath.substring(1, imgPath.length());
        Mat origin = Imgcodecs.imread(imgPath);
        new VerficationCodeOCR().doOCR(origin);
        return Result.ok();
    }

    @ApiOperation("测试3")
    @RequestMapping(value = "/test3", method = RequestMethod.GET)
    public Result<?> test3() {
        //验证码图片存储地址
        File imageFile = new File("E:\\doc\\20191108121054.png");
        if (!imageFile.exists()) {
            System.out.println("图片不存在");
            ;
        }
        Tesseract tessreact = new Tesseract();
        tessreact.setDatapath("D:\\Program Files\\Tesseract-OCR\\tessdata");

        String result = "";
        try {
            result = "测验结果：" + tessreact.doOCR(imageFile);
            System.out.println(result);
        } catch (TesseractException e) {
            e.printStackTrace();
        }
        return Result.ok(result);
    }


    @ApiOperation("测试4")
    @RequestMapping(value = "/test4", method = RequestMethod.GET)
    public Result<?> test4() {
        //验证码图片存储地址
        File imageFile = new File("E:\\doc\\20191108121054.png");
        if (!imageFile.exists()) {
            System.out.println("图片不存在");
            ;
        }
        ITesseract instance = new Tesseract();
        instance.setDatapath("D:\\Program Files\\Tesseract-OCR\\tessdata");
        //instance.setLanguage("test");
        String result = "";
        try {
            result = "测验结果：" + instance.doOCR(imageFile);
            System.out.println(result);
        } catch (TesseractException e) {
            e.printStackTrace();
        }
        return Result.ok(result);
    }


    @ApiOperation("测试5")
    @RequestMapping(value = "/test5", method = RequestMethod.GET)
    public Result<?> test5() {
        OpenCV.loadShared();
        OpenCV.loadLocally();
        //保存验证码的文件夹
        Map<String, String> map = new HashMap<>();
        try {
            String address = "E:\\doc";
            File imgFile = new File(address + "\\unFormPic");
            //验证码保存地址
            String downAddress = address + "\\unFormPic\\";
            //验证码下载地址
            //String downURL = "https://www.qichamao.com/usercenter/varifyimage?t=0.6488481170232967";
            String downURL = "http://59.204.145.208:10000/servlet/validateCode.spng?t=0.6488481170232967";
            if (imgFile.listFiles().length < 400) {
                for (int i = 1; i <= 400; i++) {
                    downloadPic(downURL, downAddress + i + ".png");
                    Thread.sleep(10 + (i % 100));
                }
            }

            //获取保存的验证码并转换为tif格式（Tesseract不支持识别gif图片）
            File imgFile0 = new File(address + "\\unFormPic");
            for (File image : imgFile0.listFiles()) {
                changePicFormat("tif", image, address + "\\formedPic\\");
            }
            System.out.println("图片格式转换成功");

            //获取转换为tif格式后的验证码，并进行加工（图片去噪，二值化），增加验证码识别度
            int picNum = 1;
            File imageFile1 = new File(address + "\\formedPic");
            for (File image : imageFile1.listFiles()) {
                filterPic(image.getName(), picNum + ".tif", address);
                picNum++;
            }

            //获取加工后的
            File resultImgs = new File(address + "\\result_cut");
            for (File link : resultImgs.listFiles()) {
                String reslut = getResult(link);
                System.out.println(link.getName() + "识别结果：" + reslut);
                map.put(link.getName(), reslut);
            }
        } catch (Exception e) {
            return Result.error("失败");
        }
        return Result.ok(map);
    }


    @ApiOperation("网格化验证码识别")
    @RequestMapping(value = "/readUntilCode", method = RequestMethod.GET)
    public Result<?> readUntilCode(String downURL, String address) {
        OpenCV.loadShared();
        OpenCV.loadLocally();
        //保存验证码的文件夹
        Map<String, String> back = new HashMap();
        try {
            address = StringUtils.isBlank(address) ? "E:\\doc2" : address;
            String imgAddress = StringUtils.isBlank(address) ? "E:\\doc2\\unFormPic" : address + "\\unFormPic";
            File imgFile = new File(imgAddress);
            //验证码保存地址
            String downAddress = imgAddress + "\\";
            //验证码下载地址
            //String downURL = "https://www.qichamao.com/usercenter/varifyimage?t=0.6488481170232967";
            downURL = StringUtils.isBlank(downURL) ? "http://59.204.145.208:10000/servlet/validateCode.spng?t=0.6488481170232967" : downURL;


//            if (imgFile.listFiles().length < 400) {
//                for (int i = 1; i <= 400; i++) {
//                    downloadPic(downURL, downAddress + i + ".png");
//                    Thread.sleep(10 + (i % 100));
//                }
//            }

            for (int i = 1; i < 100; i++) {
                downloadPic(downURL, downAddress + i + ".png");
                //获取保存的验证码并转换为tif格式（Tesseract不支持识别gif图片）
                File imgFile0 = new File(imgAddress);
                for (File image : imgFile0.listFiles()) {
                    changePicFormat("tif", image, address + "\\formedPic\\");
                }
                System.out.println("图片格式转换成功");

                //获取转换为tif格式后的验证码，并进行加工（图片去噪，二值化），增加验证码识别度
                File image = new File(address + "\\formedPic\\" + i + ".tif");
                filterPic(image.getName(), i + ".tif", address);
                //获取加工后的
                File resultImgs = new File(address + "\\result_cut\\" + i + ".tif");
                String reslut = getResult(resultImgs);
                System.out.println(resultImgs.getName() + "识别结果：" + reslut);
                if (reslut.endsWith("\n")) {
                    reslut = reslut.substring(0, reslut.length() - 1).trim();
                }

                if (reslut.length() == 6) {
                    boolean flag = isNumber(reslut);
                    if (flag) {
                        back.put("code", reslut);
                        break;
                    }
                }
            }
        } catch (Exception e) {
            return Result.error("失败");
        }
        return Result.ok(back);
    }

    public static boolean isNumber(String str) {
        char data[] = str.toCharArray();
        for (int i = 0; i < data.length; i++) {
            if (data[i] < '0' || data[i] > '9') {
                return false;
            }
        }
        return true;
    }

    // 图片处理及处理后的图片储存
    public static void filterPic(String imgName, String fileName, String address) throws FileNotFoundException, IOException {
        // 图片去噪
        Mat src = Imgcodecs.imread(address + "\\formedPic\\" + imgName, Imgcodecs.IMREAD_UNCHANGED);
        Mat dst = new Mat(src.width(), src.height(), CvType.CV_8UC1);

        if (src.empty()) {
            System.out.println("没有图片");
        } else {
            System.out.println("图片处理成功");
        }

        Imgproc.boxFilter(src, dst, src.depth(), new Size(3.2, 3.2));
        Imgcodecs.imwrite(address + "\\filter\\" + fileName, dst);

        // 图片阈值处理，二值化
        Mat src1 = Imgcodecs.imread(address + "\\filter\\" + fileName, Imgcodecs.IMREAD_UNCHANGED);
        Mat dst1 = new Mat(src1.width(), src1.height(), CvType.CV_8UC1);

        Imgproc.threshold(src1, dst1, 165, 200, Imgproc.THRESH_TRUNC);
        Imgcodecs.imwrite(address + "\\process\\" + fileName, dst1);

        // 图片截取
        Mat src2 = Imgcodecs.imread(address + "\\process\\" + fileName, Imgcodecs.IMREAD_UNCHANGED);
        Rect roi = new Rect(4, 2, src2.cols() - 7, src2.rows() - 4); // 参数：x坐标，y坐标，截取的长度，截取的宽度
        Mat dst2 = new Mat(src2, roi);

        Imgcodecs.imwrite(address + "\\result_cut\\" + fileName, dst2);

    }

    // 获取验证码
    public static String getResult(File imageFile) {
        if (!imageFile.exists()) {
            System.out.println("图片不存在");
        }
        Tesseract tessreact = new Tesseract();
        tessreact.setDatapath("D:\\Program Files\\Tesseract-OCR\\tessdata");
        //tessreact.setLanguage("fontyp");    //将默认库设置为自己训练的库
        String result;
        try {
            result = tessreact.doOCR(imageFile);
//            Mat origin = Imgcodecs.imread(imageFile.getPath());
//            new VerficationCodeOCR().doOCR(origin);
            return result;
        } catch (TesseractException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 图片格式转换
     *
     * @param outputFormat 转换的格式
     * @param image        要转换的图片
     * @param downAddress  转换后保存的地址
     * @sourse: http://www.open-open.com/code/view/1453300186683
     */
    public static void changePicFormat(String outputFormat, File image, String downAddress) {

        try {
            BufferedImage bim = ImageIO.read(image);
            File output = new File(
                    downAddress + image.getName().substring(0, image.getName().lastIndexOf(".") + 1) + outputFormat);
            ImageIO.write(bim, outputFormat, output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 下载验证码
     *
     * @param picUrl     验证码获取地址
     * @param imgAddress 图片保存地址
     */
    public static void downloadPic(String picUrl, String imgAddress) {
        try {
//            URL url = new URL(picUrl);
//            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
//            //需要设置头信息，否则会被识别为机器而获取不到验证码图片
//            conn.setRequestProperty("User-Agent",
//                    "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.75 Safari/537.36");
//            conn.connect();
//            String url = "http://59.204.145.208:10000/servlet/validateCode.spng";
//            Map<String, String> header = new HashMap<>();
//            header.put("Accept", "image/webp,image/apng,image/*,*/*;q=0.8");
//            header.put("Accept-Encoding", "gzip, deflate");
//            header.put("Accept-Language", "zh-CN,zh;q=0.9");
//            header.put("Connection", " keep-alive");
//            //Cookie: Secure; Secure; loginName=nphuanght; loginPwd=Pchbj12369; JSESSIONID=3A14E18837BA3734F3CBFC3A5650AC4F; UAM_SESSIONID=AA9FECE4B2AE0F25451C95B8E501FBC2
//            header.put("Host", "59.204.145.208:10000");
//            header.put("Referer", "http://59.204.145.208:10000/npLogin");
//            header.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36");
//            Map<String, Object> param = new HashMap<>();
//            param.put("t", 0.9903605880758632);
//            HttpResponse response = HttpRequest.get(url).addHeaders(header).execute();
            HttpClient httpclient = new DefaultHttpClient();// 创建默认http连接
            HttpGet get = new HttpGet("http://59.204.145.208:10000/servlet/validateCode.spng?t=0.7293091255670676");// 创建一个get请求
            org.apache.http.HttpResponse response = httpclient.execute(get);// 用http连接去执行get请求并且获得http响应

            HttpEntity entity = response.getEntity();// 从response中取到响实体
            int result = -1;
            byte[] buf = new byte[1024];
            BufferedInputStream bis = new BufferedInputStream(entity.getContent());
            FileOutputStream fos = new FileOutputStream(imgAddress);
            while ((result = bis.read(buf)) != -1) {
                fos.write(buf);
            }
            fos.flush();

            fos.close();
            bis.close();
            System.out.println("图片下载成功");
        } catch (MalformedURLException e) {
            System.out.println("图片读取失败");
            e.printStackTrace();
        } catch (IOException e) {
            System.out.println();
            e.printStackTrace();
        }
    }
}
